package org.simpleframework.aop;

import lombok.Getter;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.simpleframework.aop.aspect.AspectInfo;
import org.simpleframework.util.ValidationUtil;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class AspectListExecutor implements MethodInterceptor {
    //被代理的类
    private Class<?> targetClass;
    //排好序的Aspect列表
    @Getter
    private List<AspectInfo> sortedAspectInfoList;

    public AspectListExecutor(Class<?> targetClass, List<AspectInfo> aspectInfoList) {
        this.targetClass = targetClass;
        this.sortedAspectInfoList = sortAspectInfoList(aspectInfoList);
    }

    /**
     * 按照order值进行升序排序，确保order值较小的aspect先被织入
     * @param aspectInfoList
     * @return
     */
    private List<AspectInfo> sortAspectInfoList(List<AspectInfo> aspectInfoList) {
        Collections.sort(aspectInfoList, new Comparator<AspectInfo>() {
            @Override
            public int compare(AspectInfo o1, AspectInfo o2) {
                return o1.getOrderIndex()-o2.getOrderIndex();
            }
        });
        return aspectInfoList;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object returnValue=null;
        if(ValidationUtil.isEmpty(sortedAspectInfoList)){ return  returnValue; }
        //1.按照Order顺序升序执行完所有Aspect的before方法
        try {
            invokeBeforeAdvices(method,args);
            //2.执行被代理类的方法
            returnValue = methodProxy.invokeSuper(proxy, args);
            //3.如果被代理的方法正常，则按照order的顺序降序完成所有Aspect的afterReturning方法
           returnValue = invokeAfterReturningAdvices(method,args,returnValue);
        }catch (Exception e){

            //4.如果被代理的方法抛出异常，则按照order的顺序降序完成所有Aspect的afterThrowing的方法
            invokeAfterThrowingAdvices(method,args,e);
        }
        return  returnValue;

    }

    //1.按照Order顺序升序执行完所有Aspect的before方法
    private void invokeBeforeAdvices(Method method, Object[] args) throws Throwable {
        for (AspectInfo aspectInfo : sortedAspectInfoList) {
            aspectInfo.getAspectObject().before(targetClass,method,args);
        }
    }
    //3.如果被代理的方法正常，则按照order的顺序降序完成所有Aspect的afterReturning方法
    private Object invokeAfterReturningAdvices(Method method, Object[] args, Object returnValue) throws Throwable {
        Object result=null;
        for(int i= sortedAspectInfoList.size()-1;i>=0;i--){
           result= sortedAspectInfoList.get(i).getAspectObject().afterReturning(targetClass,method,args,returnValue);
        }
        return result;
    }
    //4.如果被代理的方法抛出异常，则按照order的顺序降序完成所有Aspect的afterThrowing的方法
    private void invokeAfterThrowingAdvices(Method method, Object[] args, Exception e) throws Throwable {
        for(int i= sortedAspectInfoList.size()-1;i>=0;i--){
             sortedAspectInfoList.get(i).getAspectObject().afterThrowing(targetClass,method,args,e);
        }

    }


}
